package org.zhtkj.framework;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.Future;

public class TCPServer {

    private static final Logger log = LoggerFactory.getLogger(TCPServer.class);
    private volatile boolean isRunning = false;

    private EventLoopGroup bossGroup = null;
    private EventLoopGroup workerGroup = null;
    private int port;
    private TCPServerHandler tcpServerHandler;

    public TCPServer() {
    }

    public TCPServer(int port, TCPServerHandler tcpServerHandler) {
        this();
        this.port = port;
        this.tcpServerHandler = tcpServerHandler;
    }

    private void bind() throws Exception {
        this.bossGroup = new NioEventLoopGroup();
        this.workerGroup = new NioEventLoopGroup();
        try {
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(bossGroup, workerGroup);
			serverBootstrap.channel(NioServerSocketChannel.class);
			serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				public void initChannel(SocketChannel ch) throws Exception {
					//设置多长时间连接进入空闲状态
					ch.pipeline().addLast(new IdleStateHandler(3, 0, 0, TimeUnit.MINUTES));
					//2048表示单条消息的最大长度，解码器在查找分隔符的时候，达到该长度还没找到的话会抛异常
					ch.pipeline().addLast(new DelimiterBasedFrameDecoder(2048, Unpooled.wrappedBuffer(new byte[] {0x7E}),
									Unpooled.wrappedBuffer(new byte[] {0x7E, 0x7E})));
					ch.pipeline().addLast(tcpServerHandler);
				}
			});
			serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
			serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
			log.info("jt808-TCP服务启动完毕,port={}", this.port);
			ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
			channelFuture.channel().closeFuture().sync();
		} catch (Exception e) {
	        this.bossGroup.shutdownGracefully();
	        this.workerGroup.shutdownGracefully();
	        e.printStackTrace();
		}
    }

    public synchronized void startServer() {
        if (this.isRunning) {
            throw new IllegalStateException(this.getName() + "已启动");
        }
        this.isRunning = true;
        new Thread(() -> {
            try {
                this.bind();
            } catch (Exception e) {
                log.info("jt808-TCP服务启动出错:{}", e.getMessage());
                e.printStackTrace();
            }
        }, this.getName()).start();
    }

    public synchronized void stopServer() {
        if (!this.isRunning) {
            throw new IllegalStateException(this.getName() + "未启动");
        }
        this.isRunning = false;
        try {
            Future<?> future = this.workerGroup.shutdownGracefully().await();
            if (!future.isSuccess()) {
                log.error("workerGroup 无法正常停止:{}", future.cause());
            }

            future = this.bossGroup.shutdownGracefully().await();
            if (!future.isSuccess()) {
                log.error("bossGroup 无法正常停止:{}", future.cause());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("jt808-TCP服务已经停止");
    }

    private String getName() {
        return "jt808-TCP-Server";
    }
}